#include<iostream>
#include<pthread.h>
#include<unistd.h>
#include<stdio.h>
#include <sys/types.h>
#include <sys/syscall.h>  
#include<string.h>
//int syscall(int number, ...);
using namespace std;
/*
void* StartRoutine(void*args)
{
    char*name=static_cast<char*> (args);  
    int cnt=5;
    while(cnt)
    {
        //pthread_self() 获取线程id,这个是用户级的,本质是描述线程结构体的地址
        printf("正在运行---id: 0x%x,name: %s,pid: \n",pthread_self(),args,getpid());
        sleep(1);
        cnt--;
        return (void*)10;
    }
    return (void*)10;
}


int main()
{
    pthread_t tid; 
    int *ret;
    pthread_create(&tid,nullptr,StartRoutine,(void*)"thread");
    int cnt=10;
    while(cnt)
    {
        printf("正在运行-------pid: %d\n",getpid());
        sleep(1);
        cnt--;
    }
    //int pthread_join(pthread_t thread, void **retval);
    // pthread_join(tid,nullptr);  //不接收返回值，就传入nullptr
    pthread_join(tid,(void**)&ret);//退出码
    cout<<(long long)ret<<endl;    //指针在64位系统下为8个字节
    return 0;
}
*/

/*
//线程终止(不终止整个进程)的三种方法
//1.return
//2.该线程调用pthread_exit()
//3.一个线程可以调用pthread_cancel函数终止同一进程中的另一个线程。(可以取消自己)
void* StartRoutine(void*args)
{
    char*name=static_cast<char*> (args);  
    int cnt=5;
    while(cnt)
    {
        printf("正在运行---id: 0x%x,name: %s,pid: \n",pthread_self(),args,getpid());
        sleep(1);
        cnt--;
        //pthread_exit((void*)20);

    }
    return (void*)10;
}


int main()
{
    pthread_t tid; //线程的id (用户级)线程库中的tcb的地址 （最低还是最高）？
    int *ret;
    pthread_create(&tid,nullptr,StartRoutine,(void*)"thread");
    int cnt=15;
    while(cnt)
    {
        printf("正在运行-------pid: %d\n",getpid());
        sleep(1);
        cnt--;
       // pthread_cancel(tid);
    }
    pthread_exit((void*)10);  //主线程退出 如果子线程此时还没有退出，父线程会变成僵尸进程

    //int pthread_join(pthread_t thread, void **retval);
    // pthread_join(tid,nullptr);  //不接收返回值，就传入nullptr
    pthread_join(tid,(void**)&ret);//退出码
    cout<<(long long)ret<<endl;    //指针在64位系统下为8个字节
    return 0;
}
*/


/*
//全局变量和局部存储

__thread int global_value = 100;

//验证得，从线程角度来看，这个变量的地址比结构体的起始地址要低，说明结构体地址取得可能是高地址(待定)
void* StartRoutine(void*args)
{
    char*name=static_cast<char*> (args);  
    int cnt=5;
    //gettid()不能直接用
    //syscall(SYS_gettid)
    while(cnt)
    {
        printf("正在运行---id: 0x%x,name: %s,pid: %d,gettid():%d,&global_calue:0x%x\n",pthread_self(),args,
        getpid(),syscall(SYS_gettid),&global_value);
        sleep(1);
        cnt--;
    }
    return (void*)10;
}


int main()
{
    pthread_t tid; 
    //线程的id :(用户级)线程库中的tcb的地址,直接打印上面的tid即可   
    //tid等于lwp(light weight process) ：是系统级的标识符 和pid类似 主线程的pid和tid相同
    int *ret;
    pthread_create(&tid,nullptr,StartRoutine,(void*)"thread");
    int cnt=10;
    while(cnt)
    {
        printf("主线程正在运行-------pid: %d, id:0x%x,&global_value:0x%x\n",getpid(),tid,
                                                                    &global_value);
        sleep(1);
        cnt--;
    }

    pthread_join(tid,(void**)&ret);//退出码
    cout<<(long long)ret<<endl;    //指针在64位系统下为8个字节
    return 0;
}

*/


//分离线程 detach:自动释放某些线程，不需要自己来回收 
//一个线程不能是即等待又分离
//分离线程方法一般两种 偏向在主线程分离
//1.在主线程分离 ：pthread_detach(tid);
//2.在某些线程内部分离 ：pthread_detach(pthread_self());
__thread int global_value = 100;
void *startRoutine(void *args)
{
    pthread_detach(pthread_self());
    cout << "线程分离..." << endl;
    while (true)
    {
        cout << "thread" << pthread_self() << " global_value: " << global_value
             << " Inc: " << global_value++ << "lwp: " << syscall(SYS_gettid) << endl;
        sleep(1);
    }
}
int main()
{
    pthread_t tid1;
    pthread_t tid2;
    pthread_t tid3;
    pthread_create(&tid1, nullptr, startRoutine, (void *)"thread 1");
    pthread_create(&tid2, nullptr, startRoutine, (void *)"thread 1");
    pthread_create(&tid3, nullptr, startRoutine, (void *)"thread 1");
    sleep(1);  //
    int n = pthread_join(tid1, nullptr);
    cout << n << ":" << strerror(n) << endl;
    n = pthread_join(tid2, nullptr);
    cout << n << ":" << strerror(n) << endl;
    n = pthread_join(tid3, nullptr);
    cout << n << ":" << strerror(n) << endl;
    return 0;
}
